/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#ifndef __DYNAMICARRAY_H__
#define __DYNAMICARRAY_H__

#include <string.h>
#include <exception>
#include "../Types/Types.h"

#define _ARRAY_POOL_SIZE 10

template <class T>
class DynamicArray {
private:
	cInt mSize;
	cInt mPoolSize;
	T *mTable;

	cVoid ExpandArray();
	cVoid CutArray();

public:
	/**************************************************************
    * Constructors                                                *
    ***************************************************************/
	DynamicArray();
	DynamicArray(const DynamicArray<T> &v);
	DynamicArray(cInt n);
	~DynamicArray();

	/**************************************************************
    * Operators                                                   *
    ***************************************************************/
	T& operator[](cInt i);
	DynamicArray<T>& operator=(const DynamicArray<T>& v);

	/**************************************************************
    * Other helpful functions                                     *
    ***************************************************************/
	cVoid Delete(cInt i);
	cVoid Clear();
	cVoid Add(T value);
	cVoid Add();
	cInt GetSize();
};                                                                

/**************************************************************
* Constructors                                                *
***************************************************************/
template <class T>
DynamicArray<T>::DynamicArray(): mSize(0), mPoolSize(0), mTable(cNull) {
	ExpandArray();
}

template <class T>
DynamicArray<T>::DynamicArray(const DynamicArray<T> &v) {
	delete []mTable;
	mSize = v.mSize;
	mPoolSize = v.mPoolSize;
	mTable = new T[mPoolSize];
	for (cInt i = 0; i < mSize; ++i) {
		mTable[i] = v.mTable[i];
	}
}

template <class T>
DynamicArray<T>::DynamicArray(cInt n): mSize(n) {
	cInt m = n;
	m /= _ARRAY_POOL_SIZE;
	m *= _ARRAY_POOL_SIZE;
	if (m < n) {
		m += _ARRAY_POOL_SIZE;
	}

	mPoolSize = m;
	mTable = new T[mPoolSize];
}

template <class T>
DynamicArray<T>::~DynamicArray() {
	delete []mTable;
}

/**************************************************************
* Operators                                                   *
***************************************************************/
template <class T>
cVoid DynamicArray<T>::ExpandArray() {
	T *temp;

	mPoolSize += _ARRAY_POOL_SIZE;
	temp = new T[mPoolSize];
	if (mTable != cNull) {
 		for (cInt i = 0; i < mSize - 1; ++i) {
			temp[i] = mTable[i];
		}
		delete []mTable;
	}
	mTable = temp;
}

template <class T>
cVoid DynamicArray<T>::CutArray() {
	T *temp;

	if (mSize <= mPoolSize - _ARRAY_POOL_SIZE) {
		mPoolSize -= _ARRAY_POOL_SIZE;
		temp = new T[mPoolSize];
		if (mTable != cNull) {
			for (cInt i = 0; i < mSize; ++i) {
				temp[i] = mTable[i];
			}
			delete []mTable;
		}
		mTable = temp;
	}
}

template <class T>
T& DynamicArray<T>::operator[](cInt i) {
	if (i < 0 || i >= mSize) {
		throw std::exception();
	}

	return mTable[i];
}

template <class T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray<T>& v) {
	if (&v != this) {
		if (mTable != cNull) {
			delete []mTable;
		}
		mSize = v.mSize;
		mPoolSize = v.mPoolSize;
		mTable = new T[mPoolSize];
		for (cInt i = 0; i < mSize; ++i) {
			mTable[i] = v.mTable[i];
		}
	}
	return *this;
}

/**************************************************************
* Other helpful functions                                     *
***************************************************************/
template <class T>
cVoid DynamicArray<T>::Delete(cInt i) {
	if (i >= mSize || i < 0) {
		return;
	}
	T* temp = new T[mSize - 1];
	cInt j = 0;
	for (; j < i; j++) {
		temp[j] = mTable[j];
	}
	while (j < mSize - 1) {
		temp[j] = mTable[++j];
	}
	delete []mTable;
	mTable = temp;
	mSize--;
	CutArray();
}

template <class T>
cVoid DynamicArray<T>::Clear() {
	if (mTable != cNull) {
		delete []mTable;
	}
	mTable = cNull;
	mSize = 0;
	mPoolSize = 0;
	ExpandArray();
}

template <class T>
cVoid DynamicArray<T>::Add(T value) {
	if (++mSize > mPoolSize) {
		ExpandArray();
	}
	mTable[mSize - 1] = value;
}

template <class T>
cVoid DynamicArray<T>::Add() {
	if (++mSize > mPoolSize) {
		ExpandArray();
	}
}

template <class T>
cInt DynamicArray<T>::GetSize() {
	return mSize;
}

#endif // __DYNAMICARRAY_H__